#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <string.h>
#include "process.h"

#if 0
struct sockaddr {
	sa_family_t sa_family;       // 地址族协议, ipv4
	char        sa_data[14];     // 端口(2字节) + IP地址(4字节) + 填充(8字节)
}

struct in_addr
{
    in_addr_t s_addr;
};  

struct sockaddr_in
{
    sa_family_t sin_family;		/* 地址族协议: AF_INET */
    in_port_t sin_port;         /* 端口, 2字节-> 大端  */
    struct in_addr sin_addr;    /* IP地址, 4字节 -> 大端  */
    /* 填充 8字节 */
    unsigned char sin_zero[sizeof (struct sockaddr) - sizeof(sin_family) -
               sizeof (in_port_t) - sizeof (struct in_addr)];
};  
#endif

using namespace std;
typedef struct sockaddr sockaddr;
typedef struct sockaddr_in sockaddr_in;


void *sock_accept(void *arg)
{
    sock_info_t *sock_info = (sock_info_t *)arg;
    int connect_fd = sock_info->fd;
    struct sockaddr_in client_socketaddr = sock_info->sock_addr;
    char data_buf[SOCK_BUFF_LEN];
    int rev_len = 0;
    char client_ip[32];
    socklen_t ip_len = 32;

    if (connect_fd == -1) {
        printf("Thread %lu, fail to accept\n", pthread_self());
        return NULL;
    }

    while (1) {
        bzero(data_buf, SOCK_BUFF_LEN);

        rev_len = recv(connect_fd, data_buf, SOCK_BUFF_LEN, 0);
        if(rev_len > 0) {
            inet_ntop(AF_INET, (const void *)&client_socketaddr.sin_addr, client_ip, ip_len); 
            printf("client ip addr %s, port %u\n", client_ip, ntohs(client_socketaddr.sin_port));
            printf("client say: %s\n", data_buf);

            char data_resp[SOCK_BUFF_LEN];
            const char *resp = "I am server, I have receive your message: ";
            memcpy(data_resp, resp, strlen(resp));
            memcpy(data_resp + strlen(resp), data_buf, strlen(data_buf));
            send(connect_fd, data_resp, SOCK_BUFF_LEN, 0);
        } else if (rev_len == 0) {
            printf("client close\n") ;
            break;
        } else {
            perror("Receive error");
        }
        sleep(1);
    }
    close(connect_fd);

    return NULL;
}

int thread_add_socket_task(thread_pool_t *thread_pool, sock_info_t *sock_info)
{
    int fd = sock_info->fd;
    if (fd < 0)
    {
        perror("File description error");
        return FALSE;
    }
    pthread_mutex_lock(&thread_pool->thread_pool_mutex);
    printf("%s %d: thread pool live thread num %d\n", __func__, __LINE__, thread_pool->work_thread_live);
    if (thread_pool->shutdown == 1)
    {
        printf("%s %d: Thread pool shutdown, cannot add new task\n", __func__, __LINE__);
        pthread_mutex_unlock(&thread_pool->thread_pool_mutex);
        return FALSE;
    }

    if (thread_pool->task_list_capacity > thread_pool->task_list_cur_size) {
        thread_task_t *task_list = thread_pool->task_list;
        int task_capacity = thread_pool->task_list_capacity;

        task_list[thread_pool->task_list_tail % task_capacity].function = sock_accept;
        task_list[thread_pool->task_list_tail % task_capacity].arg = (void *)sock_info;
        thread_pool->task_list_tail = (thread_pool->task_list_tail + 1) % thread_pool->task_list_capacity;
        thread_pool->task_list_cur_size++;
        pthread_mutex_unlock(&thread_pool->thread_pool_mutex);
        pthread_cond_signal(&thread_pool->consumer_num);
        
    } else {
        printf("%s %d: Task list is full, no space for new task\n",
               __func__, __LINE__);
        pthread_cond_wait(&thread_pool->producer_num, &thread_pool->thread_pool_mutex);
    }

    return TRUE;
}

/*For socket server*/

#define PORT 9999

int main()
{
    int ret = 0;
    sockaddr_in server_sockaddr;

    int listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (listen_fd == -1) {
        perror("Fail to init socket");
        return -1;
    }
    
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(PORT);
    const char *server_ip = "192.168.107.135";
    inet_pton(AF_INET, server_ip, &server_sockaddr.sin_addr.s_addr);

    ret = bind(listen_fd, (sockaddr *)(&server_sockaddr), sizeof(sockaddr));
    if (ret == -1) {
        perror("Fail to bind socket");
    }

    ret = listen(listen_fd, 128);
    if (ret == -1) {
        perror("Fail to bind socket");
    }
    thread_pool_t *thread_pool = thread_pool_create(20, 128, 128);
    int connect_fd = 0;
    sock_info_t *sock_info = NULL;
    sockaddr_in client_socketaddr;
    socklen_t socket_len = sizeof(client_socketaddr);

    printf("Start server, can accept dst-ip %s, port %u\n", server_ip, PORT);
    int counter = 0;
    while (1) {
        connect_fd = accept(listen_fd, (sockaddr *)&client_socketaddr, &socket_len);
        if (connect_fd == -1) {
            perror("Something error when connection");
            continue;
        }
        sock_info = (sock_info_t *)malloc(sizeof(sock_info_t));
        if (sock_info == NULL) {
            perror("Fail to alloc for sock info");
            continue;
        }
        sock_info->fd = connect_fd;
        memcpy(&sock_info->sock_addr, &client_socketaddr, sizeof(sockaddr_in));
        thread_add_socket_task(thread_pool, sock_info);
        counter ++;
        if (counter == 128) {
            break;
        }
    }
    /*Here I just test for 15 seconds*/
    sleep(15);
    thread_pool_destroy(thread_pool);
    close(listen_fd);

    return 0;
}

